home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / PhaseShiftX / Source / PhaseShift / main.cp < prev    next >
Encoding:
Text File  |  2001-06-23  |  10.3 KB  |  412 lines

  1. #ifdef __cplusplus
  2. extern "C" {
  3. #endif
  4.  
  5. #include <mach/mach_traps.h>
  6. #include <mach/vm_map.h>
  7.  
  8. #ifdef __cplusplus
  9. }
  10. #endif
  11.  
  12. #include <Carbon/Carbon.h>
  13. #include <CoreServices/CoreServices.h>
  14. #include <sys/mman.h>
  15. #include <sys/ptrace.h>
  16. #include <sys/types.h>
  17. #include <unistd.h>
  18. #include "MachOUtils.h"
  19.  
  20.  
  21.  
  22. #ifdef __cplusplus
  23. extern "C" {
  24. #endif
  25.  
  26. int main(int argc,char *argv[]);
  27. char *SetAppDir(char *dst,char *argv0);
  28. char *BuildSubPath(char *dst,char *path,char *subpath);
  29. mach_port_t GetFinderTask(ProcessSerialNumber *psn,pid_t *pid);
  30. void SendPingAppleEvent(ProcessSerialNumber *psn);
  31. UInt32 ReadTaskUInt32(mach_port_t task,UInt32 addr);
  32. void WriteTaskUInt32(mach_port_t task,UInt32 addr,UInt32 data);
  33.  
  34. #ifdef __cplusplus
  35. }
  36. #endif
  37.  
  38.  
  39.  
  40. #define kPowerPlantPath                "/System/Library/PrivateFrameworks/PowerPlant.framework/PowerPlant"
  41. #define kLibSystemPath                "/usr/lib/libSystem.B.dylib"
  42. #define kFinderPatchSubPath            "Resources/FinderPatch"
  43. #define kFinderPatchEntry            "_Initialize"
  44.  
  45.  
  46.  
  47. #define LI32(op,data)    do { UInt32 *_op = (UInt32*)(op),_data = (UInt32)(data);            \
  48.                              _op[0] = (_op[0] & 0xFFFF0000) | ((_data >> 16) & 0xFFFF);        \
  49.                              _op[1] = (_op[1] & 0xFFFF0000) | (_data & 0xFFFF);                \
  50.                         } while(false)
  51.  
  52.  
  53.  
  54. UInt32                        gLibSystem_DYLDFuncLookUpVector = 4 + (UInt32)FindSectionAddress(kLibSystemPath,"__DATA","__dyld");
  55. UInt32                        gPowerPlant_AEProcessAppleEventVector = (UInt32)FindSymbolAddress(kPowerPlantPath,"_AEProcessAppleEvent");
  56. char                        gAppPath[PATH_MAX];
  57. char                        gFinderPatchPath[PATH_MAX];
  58. UInt32                        gPatchCode[] = {
  59.     0x7C0802A6, 0xBE61FFCC, 0x90010008, 0x9421FF80, 0x90610098, 0x3EA00000, 0x62B50000, 0x3EC00000,
  60.     0x62D60000, 0x3EE00000, 0x62F70000, 0x3F000000, 0x63180000, 0x3F200000, 0x63390000, 0x3F400000,
  61.     0x635A0000, 0x3F600000, 0x637B0000, 0x3F800000, 0x639C0000, 0x3FA00000, 0x63BD0000, 0x3FC00000,
  62.     0x63DE0000, 0x3FE00000, 0x63FF0000, 0x92B60000, 0x7FE803A6, 0x7FC3F378, 0x38810038, 0x4E800021,
  63.     0x83C10038, 0x7FC803A6, 0x7FA3EB78, 0x38810038, 0x38A1003C, 0x4E800021, 0x83A10038, 0x7FC803A6,
  64.     0x7F83E378, 0x38810038, 0x38A1003C, 0x4E800021, 0x83810038, 0x7FC803A6, 0x7F63DB78, 0x38810038,
  65.     0x38A1003C, 0x4E800021, 0x83610038, 0x7FC803A6, 0x7F43D378, 0x38810038, 0x38A1003C, 0x4E800021,
  66.     0x83410038, 0x7FC803A6, 0x7F23CB78, 0x38810038, 0x38A1003C, 0x4E800021, 0x83210038, 0x7FA803A6,
  67.     0x7F03C378, 0x38810038, 0x4E800021, 0x82810038, 0x7F8803A6, 0x7E83A378, 0x7F04C378, 0x38A00002,
  68.     0x4E800021, 0x7C731B78, 0x7F6803A6, 0x7E83A378, 0x4E800021, 0x7F4803A6, 0x7E639B78, 0x7EE4BB78,
  69.     0x4E800021, 0x7F2803A6, 0x4E800021, 0x7C6803A6, 0x4E800021, 0x80610098, 0x7EA903A6, 0x80010088,
  70.     0x38210080, 0x7C0803A6, 0xBA61FFCC, 0x4E800420 };
  71.  
  72.  
  73.  
  74. int main(int argc,char *argv[])
  75. {
  76.     ProcessSerialNumber    finderPSN;
  77.     pid_t                finderPID;
  78.     mach_port_t            finderTask;
  79.     vm_address_t        target_patch,local_patch;
  80.     char                *str;
  81.     OSStatus            err;
  82.     
  83.     if (gLibSystem_DYLDFuncLookUpVector <= 4) {
  84.         fprintf(stderr,"Unresolved vector: LibSystem_DYLDFuncLookUp");
  85.         exit(1);
  86.     }
  87.     
  88.     if (gPowerPlant_AEProcessAppleEventVector == NULL) {
  89.         fprintf(stderr,"Unresolved vector: PowerPlant_AEProcessAppleEvent");
  90.         exit(1);
  91.     }
  92.     
  93.     SetAppDir(gAppPath,argv[0]);
  94.     BuildSubPath(gFinderPatchPath,gAppPath,kFinderPatchSubPath);
  95.     
  96.     finderTask = GetFinderTask(&finderPSN,&finderPID);
  97.     if (finderTask == MACH_PORT_NULL)
  98.     {
  99.         fprintf(stderr,"Unable to locate the Finder process, quitting.\n");
  100.         exit(1);
  101.     }
  102.     
  103.     // Ensure AEProcessAppleEvent is bound.
  104.     SendPingAppleEvent(&finderPSN);
  105.     
  106.     // Stop the target so we can safely patch it.
  107.     if (ptrace(PT_ATTACH,finderPID,NULL,0) != 0)
  108.     {
  109.         fprintf(stderr,"ptrace(PT_ATTACH,finder) failed: %08lX, %s\n",(UInt32)errno,strerror(errno));
  110.         exit(1);
  111.     }
  112.     
  113.     // Allocate a page in the target process to hold our patch.
  114.     target_patch = NULL;
  115.     err = vm_allocate(finderTask,&target_patch,4096,VM_PROT_ALL);
  116.     if (err != KERN_SUCCESS)
  117.     {
  118.         errno = err;
  119.         perror("vm_allocate");
  120.         exit(1);
  121.     }
  122.     
  123.     err = vm_protect(finderTask,target_patch,4096,false,VM_PROT_ALL);
  124.     if (err != KERN_SUCCESS)
  125.     {
  126.         errno = err;
  127.         perror("vm_protect");
  128.         exit(1);
  129.     }
  130.     
  131.     // Allocate a page in our process to generate the patch.
  132.     local_patch = NULL;
  133.     err = vm_allocate(mach_task_self(),&local_patch,4096,VM_PROT_ALL);
  134.     if (err != KERN_SUCCESS)
  135.     {
  136.         errno = err;
  137.         perror("vm_allocate");
  138.         exit(1);
  139.     }
  140.     
  141.     // Generate the patch.
  142.     str = (char*)local_patch + sizeof(gPatchCode);
  143.     strcpy(str + (0 * 256),kFinderPatchEntry);
  144.     strcpy(str + (1 * 256),gFinderPatchPath);
  145.     strcpy(str + (2 * 256),"_NSAddressOfSymbol");
  146.     strcpy(str + (3 * 256),"_NSLookupSymbolInModule");
  147.     strcpy(str + (4 * 256),"_NSDestroyObjectFileImage");
  148.     strcpy(str + (5 * 256),"_NSLinkModule");
  149.     strcpy(str + (6 * 256),"_NSCreateObjectFileImageFromFile");
  150.     strcpy(str + (7 * 256),"__dyld_lookup_and_bind");
  151.     
  152.     str = (char*)target_patch + sizeof(gPatchCode);
  153.     BlockMoveData(gPatchCode,(void*)local_patch,sizeof(gPatchCode));
  154.     LI32(&((UInt32*)local_patch)[5],ReadTaskUInt32(finderTask,gPowerPlant_AEProcessAppleEventVector));
  155.     LI32(&((UInt32*)local_patch)[7],gPowerPlant_AEProcessAppleEventVector);
  156.     LI32(&((UInt32*)local_patch)[9],str + (0 * 256));
  157.     LI32(&((UInt32*)local_patch)[11],str + (1 * 256));
  158.     LI32(&((UInt32*)local_patch)[13],str + (2 * 256));
  159.     LI32(&((UInt32*)local_patch)[15],str + (3 * 256));
  160.     LI32(&((UInt32*)local_patch)[17],str + (4 * 256));
  161.     LI32(&((UInt32*)local_patch)[19],str + (5 * 256));
  162.     LI32(&((UInt32*)local_patch)[21],str + (6 * 256));
  163.     LI32(&((UInt32*)local_patch)[23],str + (7 * 256));
  164.     LI32(&((UInt32*)local_patch)[25],ReadTaskUInt32(finderTask,gLibSystem_DYLDFuncLookUpVector));
  165.     
  166.     // Transfer patch into the target process.
  167.     err = vm_write(finderTask,target_patch,local_patch,4096);
  168.     if (err != KERN_SUCCESS)
  169.     {
  170.         errno = err;
  171.         perror("vm_write");
  172.         exit(1);
  173.     }
  174.     
  175.     // Patch the vector in the target process (ie, SetTrapAddress).
  176.     WriteTaskUInt32(finderTask,gPowerPlant_AEProcessAppleEventVector,(UInt32)target_patch);
  177.     
  178.     // Deallocate our local copy of the patch.
  179.     err = vm_deallocate(mach_task_self(),local_patch,4096);
  180.     if (err != KERN_SUCCESS)
  181.     {
  182.         errno = err;
  183.         perror("vm_deallocate");
  184.         exit(1);
  185.     }
  186.     
  187.     // Resume the target.  Since this sometimes returns EBUSY just for the hell of it,
  188.     // we sleep and retry until it succeeds, or fails with a nastier error.
  189.     while(true)
  190.     {
  191.         if (ptrace(PT_DETACH,finderPID,NULL,0) != 0)
  192.         {
  193.             if (errno == EBUSY)
  194.             {
  195.                 usleep(1000);
  196.                 continue;
  197.             }
  198.             
  199.             fprintf(stderr,"ptrace(PT_DETACH,finder) failed: %08lX, %s\n",(UInt32)errno,strerror(errno));
  200.             exit(1);
  201.         }
  202.         
  203.         break;
  204.     }
  205.     
  206.     // Ensure AEProcessAppleEvent is called.
  207.     SendPingAppleEvent(&finderPSN);
  208.     return 0;
  209. }
  210.  
  211.  
  212.  
  213. char *SetAppDir(char *dst,char *argv0)
  214. {
  215.     FSRef        ref;
  216.     int            len;
  217.     OSStatus    err;
  218.     
  219.     // Build a fully qualified path by combining the CWD and the dirname
  220.     // portion of argv[0].  We also resolve any .. components, but since
  221.     // unix doesn't provide an inverse parth lookup function, we have to
  222.     // use the CoreService's File Manager APIs.
  223.     for (len = strlen(argv0);((len > 0) && (argv0[len - 1] != '/'));len -= 1) { }
  224.     sprintf(dst,"%.*s",len,argv0);
  225.     
  226.     err = FSPathMakeRef((UInt8*)dst,&ref,NULL);
  227.     if (err != noErr)
  228.     {
  229.         fprintf(stderr,"FSPathMakeRef failed: %s\n",strerror(err));
  230.         exit(1);
  231.     }
  232.     
  233.     err = FSRefMakePath(&ref,(UInt8*)dst,PATH_MAX);
  234.     if (err != noErr)
  235.     {
  236.         fprintf(stderr,"FSRefMakePath failed: %s\n",strerror(err));
  237.         exit(1);
  238.     }
  239.     
  240.     if (chdir(dst))
  241.     {
  242.         perror("chdir failed");
  243.         exit(1);
  244.     }
  245.     
  246.     printf("CWD: %s\n",dst);
  247.     return dst;
  248. }
  249.  
  250.  
  251.  
  252. char *BuildSubPath(char *dst,char *path,char *subpath)
  253. {
  254.     FSRef        ref;
  255.     int            len;
  256.     OSStatus    err;
  257.     
  258.     for (len = strlen(path);((len > 0) && (path[len - 1] != '/'));len -= 1) { }
  259.     sprintf(dst,"%.*s%s",len,path,subpath);
  260.     
  261.     err = FSPathMakeRef((UInt8*)dst,&ref,NULL);
  262.     if (err != noErr)
  263.     {
  264.         fprintf(stderr,"FSPathMakeRef failed: %s\n",strerror(err));
  265.         exit(1);
  266.     }
  267.     
  268.     err = FSRefMakePath(&ref,(UInt8*)dst,PATH_MAX);
  269.     if (err != noErr)
  270.     {
  271.         fprintf(stderr,"FSRefMakePath failed: %s\n",strerror(err));
  272.         exit(1);
  273.     }
  274.     
  275.     printf("path: %s\n",dst);
  276.     return dst;
  277. }
  278.  
  279.  
  280.  
  281. mach_port_t GetFinderTask(ProcessSerialNumber *psn,pid_t *pid)
  282. {
  283.     ProcessInfoRec        pinfo;
  284.     Str255                name;
  285.     FSSpec                spec;
  286.     mach_port_t            task;
  287.     OSStatus            err;
  288.     
  289.     psn->highLongOfPSN = 0;
  290.     psn->lowLongOfPSN = kNoProcess;
  291.     while(GetNextProcess(psn) == noErr)
  292.     {
  293.         memset(&pinfo,0,sizeof(ProcessInfoRec));
  294.         pinfo.processInfoLength = sizeof(ProcessInfoRec);
  295.         pinfo.processName = name;
  296.         pinfo.processAppSpec = &spec;
  297.         GetProcessInformation(psn,&pinfo);
  298.         if ((pinfo.processSignature != 'MACS') || (pinfo.processType != 'FNDR'))
  299.             continue;
  300.         
  301.         err = GetProcessPID(psn,pid);
  302.         if (err != noErr)
  303.         {
  304.             errno = err;
  305.             perror("GetProcessPID");
  306.             exit(1);
  307.         }
  308.         
  309.         err = task_for_pid(mach_task_self(),*pid,&task);
  310.         if (err != noErr)
  311.         {
  312.             errno = err;
  313.             perror("task_for_pid");
  314.             exit(1);
  315.         }
  316.         
  317.         return task;
  318.     }
  319.     
  320.     return MACH_PORT_NULL;
  321. }
  322.  
  323.  
  324.  
  325. void SendPingAppleEvent(ProcessSerialNumber *psn)
  326. {
  327.     AEAddressDesc    addr;
  328.     AppleEvent        event,reply;
  329.     OSStatus        err;
  330.     
  331.     err = AECreateDesc(typeProcessSerialNumber,(Ptr)psn,sizeof(ProcessSerialNumber),&addr);
  332.     if (err == noErr)
  333.     {
  334.         err = AECreateAppleEvent('hack','ping',&addr,kAutoGenerateReturnID,kAnyTransactionID,&event);
  335.         if (err == noErr)
  336.         {
  337.             err = AESend(&event,&reply,kAEWaitReply + kAENeverInteract,kAEHighPriority,kNoTimeOut,NULL,NULL);
  338.             if (err == noErr)
  339.                 AEDisposeDesc(&reply);
  340.             
  341.             AEDisposeDesc(&event);
  342.         }
  343.         
  344.         AEDisposeDesc(&addr);
  345.     }
  346. }
  347.  
  348.  
  349.  
  350. UInt32 ReadTaskUInt32(mach_port_t task,UInt32 addr)
  351. {
  352.     vm_address_t    data;
  353.     unsigned int    size;
  354.     UInt32            value;
  355.     OSStatus        err;
  356.     
  357.     err = vm_read(task,(vm_address_t)(addr & ~4095),4096,&data,&size);
  358.     if (err != KERN_SUCCESS)
  359.     {
  360.         errno = err;
  361.         perror("vm_read");
  362.         exit(1);
  363.     }
  364.     
  365.     value = *(UInt32*)(data + (addr & 4095));
  366.     
  367.     err = vm_deallocate(mach_task_self(),data,size);
  368.     if (err != KERN_SUCCESS)
  369.     {
  370.         errno = err;
  371.         perror("vm_deallocate");
  372.         exit(1);
  373.     }
  374.     
  375.     return value;
  376. }
  377.  
  378.  
  379.  
  380. void WriteTaskUInt32(mach_port_t task,UInt32 addr,UInt32 value)
  381. {
  382.     vm_address_t    data;
  383.     unsigned int    size;
  384.     OSStatus        err;
  385.     
  386.     err = vm_read(task,(vm_address_t)(addr & ~4095),4096,&data,&size);
  387.     if (err != KERN_SUCCESS)
  388.     {
  389.         errno = err;
  390.         perror("vm_read");
  391.         exit(1);
  392.     }
  393.     
  394.     *(UInt32*)(data + (addr & 4095)) = value;
  395.     
  396.     err = vm_write(task,(vm_address_t)(addr & ~4095),data,size);
  397.     if (err != KERN_SUCCESS)
  398.     {
  399.         errno = err;
  400.         perror("vm_write");
  401.         exit(1);
  402.     }
  403.     
  404.     err = vm_deallocate(mach_task_self(),data,size);
  405.     if (err != KERN_SUCCESS)
  406.     {
  407.         errno = err;
  408.         perror("vm_deallocate");
  409.         exit(1);
  410.     }
  411. }
  412.